﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;

namespace DepSoft.UI.WPF.iWatchSyncer
{
    public class BlockingQueue<T> : IEnumerable<T>
    {
        #region Private members
        private int _queueCount     = 0;
        private Queue<T> _queue     = new Queue<T>();
        private object _locker      = new object();
        private bool _haltQueue     = false;
        #endregion

        #region Public methods
        public void HaltQueue()
        {
            lock (_locker)
            {
                _haltQueue = true;
                Monitor.Pulse(_locker);
            }
        }

        public T Dequeue()
        {
            lock (_locker)
            {
                while (!_haltQueue && _queueCount <= 0)
                    Monitor.Wait(_locker);

                if (_haltQueue)
                    return default(T);

                _queueCount--;
                return _queue.Dequeue();
            }
        }

        public void Enqueue(T data)
        {
            if (data == null)
                throw new ArgumentNullException("Nothing to enqueue");

            lock (_locker)
            {
                _queue.Enqueue(data);
                _queueCount++;
                Monitor.Pulse(_locker);
            }
        }
        #endregion

        #region IEnumerable<T> Members
        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            while (true) yield return Dequeue();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable<T>)this).GetEnumerator();
        }
        #endregion
    }
}
